'use strict'

var entryFactory = require('../../../../factory/EntryFactory')

var cmdHelper = require('../../../../helper/CmdHelper'),
  eventDefinitionHelper = require('../../../../helper/EventDefinitionHelper'),
  utils = require('../../../../Utils')

var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject,
  is = require('bpmn-js/lib/util/ModelUtil').is

var forEach = require('lodash/forEach'),
  find = require('lodash/find'),
  filter = require('lodash/filter')

function getContainedActivities(element) {
  return getFlowElements(element, 'bpmn:Activity')
}

function getContainedBoundaryEvents(element) {
  return getFlowElements(element, 'bpmn:BoundaryEvent')
}

function getFlowElements(element, type) {
  return utils.filterElementsByType(element.flowElements, type)
}

function isCompensationEventAttachedToActivity(activity, boundaryEvents) {
  var activityId = activity.id
  var boundaryEvent = find(boundaryEvents, function(boundaryEvent) {
    var compensateEventDefinition = eventDefinitionHelper.getCompensateEventDefinition(boundaryEvent)
    var attachedToRef = boundaryEvent.attachedToRef
    return compensateEventDefinition && attachedToRef && attachedToRef.id === activityId
  })
  return !!boundaryEvent
}

// subprocess: only when it is not triggeredByEvent
// activity: only when it attach a compensation boundary event
// callActivity: no limitation
function canActivityBeCompensated(activity, boundaryEvents) {
  return (is(activity, 'bpmn:SubProcess') && !activity.triggeredByEvent) ||
    is(activity, 'bpmn:CallActivity') ||
    isCompensationEventAttachedToActivity(activity, boundaryEvents)
}

function getActivitiesForCompensation(element) {
  var boundaryEvents = getContainedBoundaryEvents(element)
  return filter(getContainedActivities(element), function(activity) {
    return canActivityBeCompensated(activity, boundaryEvents)
  })
}

function getActivitiesForActivityRef(element) {
  var bo = getBusinessObject(element)
  var parent = bo.$parent

  var activitiesForActivityRef = getActivitiesForCompensation(parent)

  // if throwing compensation event is in an event sub process:
  // get also all activities outside of the event sub process
  if (is(parent, 'bpmn:SubProcess') && parent.triggeredByEvent) {
    parent = parent.$parent
    if (parent) {
      activitiesForActivityRef = activitiesForActivityRef.concat(getActivitiesForCompensation(parent))
    }

  }

  return activitiesForActivityRef
}

function createActivityRefOptions(element) {
  var options = [{ value: '' }]

  var activities = getActivitiesForActivityRef(element)
  forEach(activities, function(activity) {
    var activityId = activity.id
    var name = (activity.name ? (activity.name + ' ') : '') + '(id=' + activityId + ')'
    options.push({ value: activityId, name: name })
  })

  return options
}

module.exports = function(group, element, bpmnFactory, compensateEventDefinition, elementRegistry, translate) {

  group.entries.push(entryFactory.checkbox({
    id: 'wait-for-completion',
    label: translate('Wait for Completion'),
    modelProperty: 'waitForCompletion',

    get: function(element, node) {
      return {
        waitForCompletion: compensateEventDefinition.waitForCompletion
      }
    },

    set: function(element, values) {
      values.waitForCompletion = values.waitForCompletion || false
      return cmdHelper.updateBusinessObject(element, compensateEventDefinition, values)
    }
  }))

  group.entries.push(entryFactory.selectBox({
    id: 'activity-ref',
    label: translate('Activity Ref'),
    selectOptions: createActivityRefOptions(element),
    modelProperty: 'activityRef',

    get: function(element, node) {
      var activityRef = compensateEventDefinition.activityRef
      activityRef = activityRef && activityRef.id
      return {
        activityRef: activityRef || ''
      }
    },

    set: function(element, values) {
      var activityRef = values.activityRef || undefined
      activityRef = activityRef && getBusinessObject(elementRegistry.get(activityRef))
      return cmdHelper.updateBusinessObject(element, compensateEventDefinition, {
        activityRef: activityRef
      })
    }
  }))

}
